import sys,os
from cv2 import cv2
import numpy as np
# 加载面部资料
def read_images(path, sz=None):
    """Reads the images in a given folder, resizes images on the fly if size is given.
    Args:
        path: 人面数据所在的文件路径
        sz: 图片尺寸设置
    Returns:
        A list [X,y]
            X: 图片信息
            y: 图片的读取顺序
    """
    c = 0
    X,y = [], []
    for dirname, dirnames, filenames in os.walk(path):
        for subdirname in dirnames:
            subject_path = os.path.join(dirname, subdirname)
            for filename in os.listdir(subject_path):
                filepath = os.path.join(subject_path, filename)
                im = cv2.imread(filepath, cv2.IMREAD_GRAYSCALE)
                if (sz is not None):
                    im = cv2.resize(im, sz)
                X.append(np.asarray(im, dtype=np.uint8))
                y.append(c)
            c = c+1
    
    return [X,y]

# 面部识别
def face_rec():
    names = ['cfz']
    [X, y] = read_images('C:/Users/ALEXWELL/Desktop/OpenCV_Face/auto/')
    # 创建识别模型，使用EigenFace算法识别，Confidence评分低于4000是可靠
    # model = cv2.face.EigenFaceRecognizer_create()
    # 创建识别模型，使用LBPHFace算法识别，Confidence评分低于50是可靠
    # model = cv2.face.LBPHFaceRecognizer_create()
    # 创建识别模型，使用FisherFace算法识别，Confidence评分低于4000是可靠
    model = cv2.face.LBPHFaceRecognizer_create()
    # 训练模型
    # train函数参数：images, labels，两参数必须为np.array格式，而且labels的值必须为整型
    model.train(np.array(X), np.array(y))
    # 开启摄像头
    camera = cv2.VideoCapture(0)
    # 加载Haar级联数据文件，用于检测人面
    face_cascade = cv2.CascadeClassifier('C:/Users/ALEXWELL/Desktop/OpenCV_Face/data/haarcascades/haarcascade_frontalface_default.xml')
    while (True):
        # 检测摄像头的人面
        read, img = camera.read()
        faces = face_cascade.detectMultiScale(img, 1.3, 5)
        # 将检测的人面进行识别处理
        for (x, y, w, h) in faces:
            # 画出人面所在位置并灰度处理
            img = cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            roi = gray[x:x + w, y:y + h]

            # 将检测的人面缩放200*200大小，用于识别
            # cv2.INTER_LINEAR是图片变换方式，其余变换方式如下：
            # INTER_NN - 最近邻插值。
            # INTER_LINEAR - 双线性插值(缺省使用)
            # INTER_AREA - 使用象素关系重采样。当图像缩小时候，该方法可以避免波纹出现。
            # INTER_CUBIC - 立方插值。
            roi = cv2.resize(roi, (200, 200), interpolation=cv2.INTER_LINEAR)

            # 检测的人面与模型进行匹配识别
            params = model.predict(roi)
            print("Label: %s, Confidence: %.2f" % (params[0], params[1]))
            # 将识别结果显示在摄像头上
            # cv2.FONT_HERSHEY_SIMPLEX 定义字体
            # cv2.putText参数含义：图像，文字内容， 坐标 ，字体，大小，颜色，字体厚度
            # 如果要输出中文字，可参考https://blog.csdn.net/m0_37606112/article/details/78511381
            cv2.putText(img, names[params[0]], (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 2)

        cv2.imshow("camera", img)
        if cv2.waitKey(120) & 0xff == ord("q"):
            break
    cv2.destroyAllWindows()


if __name__ == "__main__":
    face_rec()
